home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 22 / Cream of the Crop 22.iso / math / ast53src.zip / XCHARTS2.C < prev    next >
C/C++ Source or Header  |  1996-09-29  |  27KB  |  781 lines

  1. /*
  2. ** Astrolog (Version 5.30) File: xcharts2.c
  3. **
  4. ** IMPORTANT NOTICE: The graphics database and chart display routines
  5. ** used in this program are Copyright (C) 1991-1996 by Walter D. Pullen
  6. ** (Astara@msn.com, http://www.magitech.com/~cruiser1/astrolog.htm).
  7. ** Permission is granted to freely use and distribute these routines
  8. ** provided one doesn't sell, restrict, or profit from them in any way.
  9. ** Modification is allowed provided these notices remain with any
  10. ** altered or edited versions of the program.
  11. **
  12. ** The main planetary calculation routines used in this program have
  13. ** been Copyrighted and the core of this program is basically a
  14. ** conversion to C of the routines created by James Neely as listed in
  15. ** Michael Erlewine's 'Manual of Computer Programming for Astrologers',
  16. ** available from Matrix Software. The copyright gives us permission to
  17. ** use the routines for personal use but not to sell them or profit from
  18. ** them in any way.
  19. **
  20. ** The PostScript code within the core graphics routines are programmed
  21. ** and Copyright (C) 1992-1993 by Brian D. Willoughby
  22. ** (brianw@sounds.wa.com). Conditions are identical to those above.
  23. **
  24. ** The extended accurate ephemeris databases and formulas are from the
  25. ** calculation routines in the program "Placalc" and are programmed and
  26. ** Copyright (C) 1989,1991,1993 by Astrodienst AG and Alois Treindl
  27. ** (alois@azur.ch). The use of that source code is subject to
  28. ** regulations made by Astrodienst Zurich, and the code is not in the
  29. ** public domain. This copyright notice must not be changed or removed
  30. ** by any user of this program.
  31. **
  32. ** Initial programming 8/28,30, 9/10,13,16,20,23, 10/3,6,7, 11/7,10,21/1991.
  33. ** X Window graphics initially programmed 10/23-29/1991.
  34. ** PostScript graphics initially programmed 11/29-30/1992.
  35. ** Last code change made 9/22/1996.
  36. */
  37.  
  38. #include "astrolog.h"
  39.  
  40.  
  41. #ifdef GRAPH
  42. /*
  43. ******************************************************************************
  44. ** Chart Graphics Utility Procedures.
  45. ******************************************************************************
  46. */
  47.  
  48. /* Return whether the specified object should be displayed in the current */
  49. /* graphics chart type. For example, don't include the Moon in the solar  */
  50. /* system charts when Placalc is off, don't include house cusps in        */
  51. /* astro-graph charts, and so on, in addition to checking restrictions.   */
  52.  
  53. bool FProper(i)
  54. int i;
  55. {
  56.   bool f;
  57.  
  58.   f = !ignore[i] && (gi.nMode == gOrbit || i != us.objCenter);
  59.   if (gi.nMode == gHorizon || fMap || gi.nMode == gGlobe ||
  60.     gi.nMode == gPolar)                      /* Horizon and map charts */
  61.     f &= FObject(i);
  62.   else if (gi.nMode == gOrbit)               /* Solar system charts */
  63.     f &= FObject(i) && (i != oMoo || us.fPlacalc);
  64.   else if (gi.nMode == gSector || gi.nMode == gEphemeris)
  65.     f &= FThing(i);                          /* Sector amd ephemeris charts */
  66.   return f;
  67. }
  68.  
  69.  
  70. /* Adjust an array of zodiac positions so that no two positions are within   */
  71. /* a certain orb of each other. This is used by the wheel drawing chart      */
  72. /* routines in order to make sure that we don't draw any planet glyphs on    */
  73. /* top of each other. We'll later draw the glyphs at the adjusted positions. */
  74.  
  75. void FillSymbolRing(symbol, factor)
  76. real *symbol;
  77. real factor;
  78. {
  79.   real orb = DEFORB*256.0/(real)gs.yWin*(real)gi.nScale*factor, k1, k2, temp;
  80.   int i, j, k = 1, l;
  81.  
  82.   /* Keep adjusting as long as we can still make changes, or until we do 'n' */
  83.   /* rounds. (With many objects, there just may not be enough room for all.) */
  84.  
  85.   for (l = 0; k && l < us.nDivision*2; l++) {
  86.     k = 0;
  87.     for (i = 0; i <= cObj; i++) if (FProper(i)) {
  88.  
  89.       /* For each object, determine who is closest on either side. */
  90.  
  91.       k1 = rLarge; k2 = -rLarge;
  92.       for (j = 0; j <= cObj; j++)
  93.         if (FProper(j) && i != j) {
  94.           temp = symbol[j]-symbol[i];
  95.           if (RAbs(temp) > rDegHalf)
  96.             temp -= rDegMax*RSgn(temp);
  97.           if (temp < k1 && temp > 0.0)
  98.             k1 = temp;
  99.           else if (temp > k2 && temp <= 0.0)
  100.             k2 = temp;
  101.         }
  102.  
  103.       /* If an object's too close on one side, then we move to the other. */
  104.  
  105.       if (k2 > -orb && k1 > orb) {
  106.         k = 1; symbol[i] = Mod(symbol[i]+orb*0.51+k2*0.49);
  107.       } else if (k1 < orb && k2 < -orb) {
  108.         k = 1; symbol[i] = Mod(symbol[i]-orb*0.51+k1*0.49);
  109.  
  110.       /* If we are bracketed by close objects on both sides, then let's move */
  111.       /* to the midpoint, so we are as far away as possible from either one. */
  112.  
  113.       } else if (k2 > -orb && k1 < orb) {
  114.         k = 1; symbol[i] = Mod(symbol[i]+(k1+k2)*0.5);
  115.       }
  116.     }
  117.   }
  118. }
  119.  
  120.  
  121. /* Adjust an array of longitude positions so that no two are within a    */
  122. /* certain orb of each other. This is used by the astro-graph routine to */
  123. /* make sure we don't draw any planet glyphs marking the lines on top of */
  124. /* each other. This is almost identical to the FillSymbolRing() routine  */
  125. /* used by the wheel charts; however, there the glyphs are placed in a   */
  126. /* continuous ring, while here we have the left and right screen edges.  */
  127. /* Also, here we are placing two sets of planets at the same time.       */
  128.  
  129. void FillSymbolLine(symbol)
  130. real *symbol;
  131. {
  132.   real orb = DEFORB*1.35*(real)gi.nScale, max = rDegMax, k1, k2, temp;
  133.   int i, j, k = 1, l;
  134.  
  135.   if (gi.nMode != gEphemeris)
  136.     max *= (real)gi.nScale;
  137.   else
  138.     orb *= rDegMax/(real)gs.xWin;
  139.  
  140.   /* Keep adjusting as long as we can still make changes. */
  141.  
  142.   for (l = 0; k && l < us.nDivision*2; l++) {
  143.     k = 0;
  144.     for (i = 1; i <= cObj*2; i++)
  145.       if (FProper((i+1)/2) && symbol[i] >= 0.0) {
  146.  
  147.         /* For each object, determine who is closest to the left and right. */
  148.  
  149.         k1 = max-symbol[i]; k2 = -symbol[i];
  150.         for (j = 1; j <= cObj*2; j++) {
  151.           if (FProper((j+1)/2) && i != j) {
  152.             temp = symbol[j]-symbol[i];
  153.             if (temp < k1 && temp > 0.0)
  154.               k1 = temp;
  155.             else if (temp > k2 && temp <= 0.0)
  156.               k2 = temp;
  157.           }
  158.         }
  159.  
  160.         /* If an object's too close on one side, then we move to the other. */
  161.  
  162.         if (k2 > -orb && k1 > orb) {
  163.           k = 1; symbol[i] = symbol[i]+orb*0.51+k2*0.49;
  164.         } else if (k1 < orb && k2 < -orb) {
  165.           k = 1; symbol[i] = symbol[i]-orb*0.51+k1*0.49;
  166.         } else if (k2 > -orb && k1 < orb) {
  167.           k = 1; symbol[i] = symbol[i]+(k1+k2)*0.5;
  168.         }
  169.       }
  170.   }
  171. }
  172.  
  173.  
  174. /* Given a zodiac degree, adjust it if need be to account for the expanding */
  175. /* and compacting of parts the zodiac that happen when we display a graphic */
  176. /* wheel chart such that all the houses appear the same size.               */
  177.  
  178. real HousePlaceInX(deg)
  179. real deg;
  180. {
  181.   int in;
  182.  
  183.   if (gi.nMode == gWheel)    /* We only adjust for the -w -X combination. */
  184.     return deg;
  185.   in = HousePlaceIn(deg);
  186.   return Mod(ZFromS(in)+MinDistance(chouse[in], deg)/
  187.     MinDistance(chouse[in], chouse[Mod12(in+1)])*30.0);
  188. }
  189.  
  190.  
  191. /*
  192. ******************************************************************************
  193. ** Multiple Chart Graphics Routines.
  194. ******************************************************************************
  195. */
  196.  
  197. /* Draw another wheel chart; however, this time we have two rings of planets */
  198. /* because we are doing a relationship chart between two sets of data. This  */
  199. /* chart is obtained when the -r0 is combined with the -X switch.            */
  200.  
  201. void XChartWheelRelation()
  202. {
  203.   real xsign[cSign+1], xhouse1[cSign+1], xplanet1[objMax], xplanet2[objMax],
  204.     symbol[objMax];
  205.   byte ignoreT[objMax];
  206.   int cx, cy, i, j;
  207.   real asc, unitx, unity, temp;
  208.   CI ciT;
  209.  
  210.   /* Set up variables and temporarily automatically decrease the horizontal */
  211.   /* chart size to leave room for the sidebar if that mode is in effect.    */
  212.  
  213.   if (gs.fText && !us.fVelocity)
  214.     gs.xWin -= xSideT;
  215.   cx = gs.xWin/2 - 1; cy = gs.yWin/2 - 1;
  216.   unitx = (real)cx; unity = (real)cy;
  217.   asc = gs.objLeft ? cp1.obj[abs(gs.objLeft)]+90*(gs.objLeft < 0) :
  218.     cp1.cusp[1];
  219.  
  220.   /* Fill out arrays with the degree of each object, cusp, and sign glyph. */
  221.  
  222.   if (gi.nMode == gWheel) {
  223.     for (i = 1; i <= cSign; i++)
  224.       xhouse1[i] = PZ(cp1.cusp[i]);
  225.   } else {
  226.     asc -= cp1.cusp[1];
  227.     for (i = 1; i <= cSign; i++)
  228.       xhouse1[i] = PZ(ZFromS(i));
  229.   }
  230.   for (i = 1; i <= cSign; i++)
  231.     xsign[i] = PZ(HousePlaceInX(ZFromS(i)));
  232.   for (i = 0; i <= cObj; i++)
  233.     xplanet1[i] = PZ(HousePlaceInX(cp1.obj[i]));
  234.   for (i = 0; i <= cObj; i++)
  235.     xplanet2[i] = PZ(HousePlaceInX(cp2.obj[i]));
  236.  
  237.   /* Go draw the outer sign and house rings. We are drawing only the */
  238.   /* houses of one of the two charts in the relationship, however.   */
  239.  
  240.   DrawWheel(xsign, xhouse1, cx, cy, unitx, unity, asc,
  241.     0.70, 0.74, 0.78, 0.82, 0.885);
  242.  
  243.   /* Draw the outer ring of planets (based on the planets in the chart     */
  244.   /* which the houses do not reflect - the houses belong to the inner ring */
  245.   /* below). Draw each glyph, a line from it to its actual position point  */
  246.   /* in the outer ring, and then draw another line from this point to a    */
  247.   /* another dot at the same position in the inner ring as well.           */
  248.  
  249.   for (i = 0; i <= cObj; i++)
  250.     symbol[i] = xplanet2[i];
  251.   if (us.nRel == rcTransit)
  252.     for (i = 0; i <= cObj; i++) {
  253.       ignoreT[i] = ignore[i];
  254.       ignore[i] = ignore2[i];
  255.     }
  256.   FillSymbolRing(symbol, 1.0);
  257.   if (us.nRel == rcTransit)
  258.     for (i = 0; i <= cObj; i++)
  259.       ignore[i] = ignoreT[i];
  260.  
  261.   for (i = cObj; i >= 0; i--) if (FProper2(i)) {
  262.     if (gs.fLabel) {
  263.       temp = symbol[i];
  264.       DrawColor(cp2.dir[i] < 0.0 ? gi.kiGray : gi.kiOn);
  265.       DrawDash(cx+POINT1(unitx, 0.58, PX(xplanet2[i])),
  266.         cy+POINT1(unity, 0.58, PY(xplanet2[i])),
  267.         cx+POINT2(unitx, 0.61, PX(temp)),
  268.         cy+POINT2(unity, 0.61, PY(temp)),
  269.         (cp2.dir[i] < 0.0 ? 1 : 0) - gs.fColor);
  270.       DrawObject(i, cx+POINT1(unitx, 0.65, PX(temp)),
  271.         cy+POINT1(unity, 0.65, PY(temp)));
  272.     }
  273.     DrawColor(kObjB[i]);
  274.     DrawPoint(cx+POINT1(unitx, 0.56, PX(xplanet2[i])),
  275.       cy+POINT1(unity, 0.56, PY(xplanet2[i])));
  276.     DrawPoint(cx+POINT1(unitx, 0.43, PX(xplanet2[i])),
  277.       cy+POINT1(unity, 0.43, PY(xplanet2[i])));
  278.     DrawColor(cp2.dir[i] < 0.0 ? gi.kiGray : gi.kiOn);
  279.     DrawDash(cx+POINT1(unitx, 0.45, PX(xplanet2[i])),
  280.       cy+POINT1(unity, 0.45, PY(xplanet2[i])),
  281.       cx+POINT2(unitx, 0.54, PX(xplanet2[i])),
  282.       cy+POINT2(unity, 0.54, PY(xplanet2[i])), 2-gs.fColor);
  283.   }
  284.  
  285.   /* Now draw the inner ring of planets. If it weren't for the outer ring,  */
  286.   /* this would be just like the standard non-relationship wheel chart with */
  287.   /* only one set of planets. Again, draw glyph, and a line to true point.  */
  288.  
  289.   for (i = 0; i <= cObj; i++)
  290.     symbol[i] = xplanet1[i];
  291.   FillSymbolRing(symbol, 1.1);
  292.   DrawSymbolRing(symbol, xplanet1, cp1.dir, cx, cy, unitx, unity,
  293.     0.43, 0.45, 0.48, 0.52);
  294.  
  295.   /* Draw lines connecting planets between the two charts that have aspects. */
  296.  
  297.   if (!gs.fAlt) {                      /* Don't draw aspects in bonus mode. */
  298.     if (!FCreateGridRelation(fFalse))
  299.       return;
  300.     for (j = cObj; j >= 0; j--)
  301.       for (i = cObj; i >= 0; i--)
  302.         if (grid->n[i][j] && FProper2(i) && FProper(j)) {
  303.           DrawColor(kAspB[grid->n[i][j]]);
  304.           DrawDash(cx+POINT1(unitx, 0.41, PX(xplanet1[j])),
  305.             cy+POINT1(unity, 0.41, PY(xplanet1[j])),
  306.             cx+POINT1(unitx, 0.41, PX(xplanet2[i])),
  307.             cy+POINT1(unity, 0.41, PY(xplanet2[i])),
  308.             abs(grid->v[i][j]/60/2));
  309.         }
  310.   }
  311.  
  312.   /* Go draw sidebar with chart information and positions if need be. */
  313.  
  314.   if (us.nRel == rcTransit) {
  315.     ciT = ciMain;
  316.     ciMain = ciTwin;
  317.   }
  318.   DrawInfo();
  319.   if (us.nRel == rcTransit)
  320.     ciMain = ciT;
  321. }
  322.  
  323.  
  324. /* Draw a tri-wheel chart or quad-wheel chart, where we have three or four */
  325. /* rings, among three or four sets of data we're comparing. This chart is  */
  326. /* obtained when the -r3 or -r4 switch is combined with the -X switch.     */
  327.  
  328. void XChartWheelThreeFour()
  329. {
  330.   real xsign[cSign+1], xhouse1[cSign+1], xplanet1[objMax], xplanet2[objMax],
  331.     symbol[objMax];
  332.   int cx, cy, i, fQuad;
  333.   real asc, unitx, unity, base;
  334.   CP cpT;
  335.  
  336.   /* Set up variables and temporarily automatically decrease the horizontal */
  337.   /* chart size to leave room for the sidebar if that mode is in effect.    */
  338.  
  339.   if (gs.fText && !us.fVelocity)
  340.     gs.xWin -= xSideT;
  341.   cx = gs.xWin/2 - 1; cy = gs.yWin/2 - 1;
  342.   unitx = (real)cx; unity = (real)cy;
  343.   asc = gs.objLeft ? cp1.obj[abs(gs.objLeft)]+90*(gs.objLeft < 0) :
  344.     cp1.cusp[1];
  345.   fQuad = (us.nRel == rcQuadWheel);
  346.   base = (fQuad ? 0.22 : 0.35);
  347.  
  348.   /* Fill out arrays with the degrees of the cusps and sign glyphs, and the */
  349.   /* positions of the outer two rings.                                      */
  350.  
  351.   if (gi.nMode == gWheel) {
  352.     for (i = 1; i <= cSign; i++)
  353.       xhouse1[i] = PZ(cp1.cusp[i]);
  354.   } else {
  355.     asc -= cp1.cusp[1];
  356.     for (i = 1; i <= cSign; i++)
  357.       xhouse1[i] = PZ(ZFromS(i));
  358.   }
  359.   for (i = 1; i <= cSign; i++)
  360.     xsign[i] = PZ(HousePlaceInX(ZFromS(i)));
  361.   for (i = 0; i <= cObj; i++)
  362.     xplanet1[i] = PZ(HousePlaceInX(cp1.obj[i]));
  363.   for (i = 0; i <= cObj; i++)
  364.     xplanet2[i] = PZ(HousePlaceInX(cp2.obj[i]));
  365.  
  366.   /* Go draw the outer sign and house rings. We are drawing the houses */
  367.   /* of only the outermost ring of the wheel, however.                 */
  368.  
  369.   DrawWheel(xsign, xhouse1, cx, cy, unitx, unity, asc,
  370.     0.745, 0.78, 0.815, 0.84, 0.895);
  371.  
  372.   /* Draw the outer ring of planets (i.e. the one the house cusps reflect). */
  373.   /* Draw each glyph, a line from it to its actual position point in the    */
  374.   /* outer ring, and then draw another line from this point to a another    */
  375.   /* dot at the same position on the innermost ring as well.                */
  376.  
  377.   for (i = 0; i <= cObj; i++)
  378.     symbol[i] = xplanet1[i];
  379.   FillSymbolRing(symbol, 0.9);
  380.   DrawSymbolRing(symbol, xplanet1, ret, cx, cy, unitx, unity,
  381.     0.61, 0.63, 0.66, 0.70);
  382.   for (i = cObj; i >= 0; i--) if (FProper(i)) {
  383.     DrawColor(kObjB[i]);
  384.     DrawPoint(cx+POINT1(unitx, base, PX(xplanet1[i])),
  385.       cy+POINT1(unity, base, PY(xplanet1[i])));
  386.     if (gs.fAlt) {
  387.       DrawColor(ret[i] < 0.0 ? gi.kiGray : gi.kiOn);
  388.       DrawDash(cx+POINT1(unitx, base+0.02, PX(xplanet1[i])),
  389.         cy+POINT1(unity, base+0.02, PY(xplanet1[i])),
  390.         cx+POINT2(unitx, 0.59, PX(xplanet1[i])),
  391.         cy+POINT2(unity, 0.59, PY(xplanet1[i])), 3+fQuad-gs.fColor);
  392.     }
  393.   }
  394.  
  395.   /* Now draw the second to outermost ring of planets. Again, draw each */
  396.   /* glyph, a line to its true point, and a line to the innermost ring. */
  397.  
  398.   for (i = 0; i <= cObj; i++)
  399.     symbol[i] = xplanet2[i];
  400.   FillSymbolRing(symbol, 1.1);
  401.   DrawSymbolRing(symbol, xplanet2, cp2.dir, cx, cy, unitx, unity,
  402.     0.48, 0.50, 0.53, 0.57);
  403.   for (i = cObj; i >= 0; i--) if (FProper(i)) {
  404.     DrawColor(kObjB[i]);
  405.     DrawPoint(cx+POINT1(unitx, base, PX(xplanet2[i])),
  406.       cy+POINT1(unity, base, PY(xplanet2[i])));
  407.     if (gs.fAlt) {
  408.       DrawColor(cp2.dir[i] < 0.0 ? gi.kiGray : gi.kiOn);
  409.       DrawDash(cx+POINT1(unitx, base+0.02, PX(xplanet2[i])),
  410.         cy+POINT1(unity, base+0.02, PY(xplanet2[i])),
  411.         cx+POINT2(unitx, 0.46, PX(xplanet2[i])),
  412.         cy+POINT2(unity, 0.46, PY(xplanet2[i])), 2+fQuad-gs.fColor);
  413.     }
  414.   }
  415.  
  416.   /* The third ring (either the innermost or second to innermost) is next.   */
  417.   /* Cast the chart on the fly, and draw the glyphs and lines to true point. */
  418.  
  419.   ciCore = ciThre;
  420.   cpT = cp0;
  421.   CastChart(fTrue);
  422.   for (i = 0; i <= cObj; i++)
  423.     xplanet1[i] = PZ(HousePlaceInX(planet[i]));
  424.   cp0 = cpT;
  425.   for (i = 0; i <= cObj; i++)
  426.     symbol[i] = xplanet1[i];
  427.   FillSymbolRing(symbol, 1.4);
  428.   DrawSymbolRing(symbol, xplanet1, ret, cx, cy, unitx, unity,
  429.     0.35, 0.37, 0.40, 0.44);
  430.  
  431.   if (fQuad) {
  432.  
  433.     /* If a fourth ring is being done, first finish the third one by */
  434.     /* drawing lines from the true positions to the inner ring.      */
  435.  
  436.     for (i = cObj; i >= 0; i--) if (FProper(i)) {
  437.       DrawColor(kObjB[i]);
  438.       DrawPoint(cx+POINT1(unitx, base, PX(xplanet1[i])),
  439.         cy+POINT1(unity, base, PY(xplanet1[i])));
  440.       if (gs.fAlt) {
  441.         DrawColor(ret[i] < 0.0 ? gi.kiGray : gi.kiOn);
  442.         DrawDash(cx+POINT1(unitx, base+0.02, PX(xplanet1[i])),
  443.           cy+POINT1(unity, base+0.02, PY(xplanet1[i])),
  444.           cx+POINT2(unitx, 0.33, PX(xplanet1[i])),
  445.           cy+POINT2(unity, 0.33, PY(xplanet1[i])), 2-gs.fColor);
  446.       }
  447.     }
  448.  
  449.     /* If the fourth (innermost) ring is being done, cast the chart on the */
  450.     /* fly, and draw the glyphs and lines to the true positions.           */
  451.  
  452.     ciCore = ciFour;
  453.     cpT = cp0;
  454.     CastChart(fTrue);
  455.     for (i = 0; i <= cObj; i++)
  456.       xplanet2[i] = PZ(HousePlaceInX(planet[i]));
  457.     cp0 = cpT;
  458.     for (i = 0; i <= cObj; i++)
  459.       symbol[i] = xplanet2[i];
  460.     FillSymbolRing(symbol, 1.8);
  461.     DrawSymbolRing(symbol, xplanet2, ret, cx, cy, unitx, unity,
  462.       0.22, 0.24, 0.27, 0.31);
  463.   }
  464.  
  465.   /* Go draw sidebar with chart information and positions if need be. */
  466.  
  467.   ciCore = ciMain;
  468.   DrawInfo();
  469. }
  470.  
  471.  
  472. /* Draw an aspect (or midpoint) grid in the window, between the planets in  */
  473. /* two different charts, with the planets labeled at the top and side. This */
  474. /* chart is done when the -g switch is combined with the -r0 and -X switch. */
  475. /* Like above, the chart always has a (definable) fixed number of cells.    */
  476.  
  477. void XChartGridRelation()
  478. {
  479.   char sz[cchSzDef];
  480.   int unit, siz, x, y, i, j, k, l;
  481.   KI c;
  482.  
  483.   unit = CELLSIZE*gi.nScale; siz = (gs.nGridCell+1)*unit;
  484.   if (!FCreateGridRelation(gs.fAlt != us.fGridConfig))
  485.     return;
  486.   for (y = 0, j = -1; y <= gs.nGridCell; y++) {
  487.     do {
  488.       j++;
  489.     } while (ignore[j] && j <= cObj);
  490.     DrawColor(gi.kiGray);
  491.     DrawDash(0, (y+1)*unit, siz, (y+1)*unit, !gs.fColor);
  492.     DrawDash((y+1)*unit, 0, (y+1)*unit, siz, !gs.fColor);
  493.     DrawColor(gi.kiLite);
  494.     DrawEdge(0, y*unit, unit, (y+1)*unit);
  495.     DrawEdge(y*unit, 0, (y+1)*unit, unit);
  496.     if (j <= cObj) for (x = 0, i = -1; x <= gs.nGridCell; x++) {
  497.       do {
  498.         i++;
  499.       } while (ignore[i] && i <= cObj);
  500.  
  501.       /* Again, we are looping through each cell in each row and column. */
  502.  
  503.       if (i <= cObj) {
  504.         gi.xTurtle = x*unit+unit/2;
  505.         gi.yTurtle = y*unit+unit/2 -
  506.           (gi.nScale/gi.nScaleT > 2 ? 5*gi.nScaleT : 0);
  507.         k = grid->n[i][j];
  508.  
  509.         /* If current cell is on top row or left hand column, draw glyph */
  510.         /* of planet owning the particular row or column in question.    */
  511.  
  512.         if (y == 0 || x == 0) {
  513.           if (x+y > 0)
  514.             DrawObject(j == 0 ? i : j, gi.xTurtle, gi.yTurtle);
  515.         } else {
  516.  
  517.         /* Otherwise, draw glyph of aspect in effect, or glyph of */
  518.         /* sign of midpoint, between the two planets in question. */
  519.  
  520.           if (gs.fAlt == us.fGridConfig) {
  521.             if (k) {
  522.               DrawColor(c = kAspB[k]);
  523.               DrawAspect(k, gi.xTurtle, gi.yTurtle);
  524.             }
  525.           } else {
  526.             DrawColor(c = kSignB(grid->n[i][j]));
  527.             DrawSign(grid->n[i][j], gi.xTurtle, gi.yTurtle);
  528.           }
  529.         }
  530.  
  531.         /* Again, when scale size is 300+, print some text in current cell: */
  532.  
  533.         if (gi.nScale/gi.nScaleT > 2 && gs.fLabel) {
  534.  
  535.           /* For top and left edges, print sign and degree of the planet. */
  536.  
  537.           if (y == 0 || x == 0) {
  538.             if (x+y > 0) {
  539.               k = SFromZ(y == 0 ? cp2.obj[i] : cp1.obj[j]);
  540.               l = (int)((y == 0 ? cp2.obj[i] : cp1.obj[j])-ZFromS(k));
  541.               c = kSignB(k);
  542.               sprintf(sz, "%c%c%c %02d", chSig3(k), l);
  543.  
  544.               /* For extreme upper left corner, print some little arrows */
  545.               /* pointing out chart1's planets and chart2's planets.     */
  546.  
  547.             } else {
  548.               c = gi.kiLite;
  549.               sprintf(sz, "1v 2->");
  550.             }
  551.           } else {
  552.             k = abs(grid->v[i][j]);
  553.  
  554.             /* For aspect cells, print the orb in degrees and minutes. */
  555.  
  556.             if (gs.fAlt == us.fGridConfig) {
  557.               if (grid->n[i][j])
  558.                 sprintf(sz, "%c%d %02d'", k != grid->v[i][j] ?
  559.                   (us.fAppSep ? 'a' : '-') : (us.fAppSep ? 's' : '+'),
  560.                   k/60, k%60);
  561.               else
  562.                 sprintf(sz, "");
  563.  
  564.             /* For midpoint cells, print degree and minute. */
  565.  
  566.             } else
  567.               sprintf(sz, "%2d %02d'", k/60, k%60);
  568.           }
  569.           DrawColor(c);
  570.           DrawSz(sz, x*unit+unit/2, (y+1)*unit-3*gi.nScaleT, dtBottom);
  571.         }
  572.       }
  573.     }
  574.   }
  575. }
  576.  
  577.  
  578. /* Draw a chart showing a graphical ephemeris for the given month (or year */
  579. /* if -Ey in effect), with the date on the vertical access and the zodiac  */
  580. /* on the horizontal, as done when the -E is combined with the -X switch.  */
  581.  
  582. void XChartEphemeris()
  583. {
  584.   real symbol[cObj*2+1], objSav[objMax];
  585.   char sz[4];
  586.   int yea, unit = 6*gi.nScale, daytot, d = 1, day, mon, monsiz,
  587.     x1, y1, x2, y2, xs, ys, m, n, u, v, i, j;
  588.  
  589.   yea = us.nEphemYears;    /* Is this -Ey -X or just -E -X? */
  590.   if (yea) {
  591.     daytot = DayInYearHi(Yea);
  592.     day = 1; mon = 1; monsiz = 31;
  593.   } else
  594.     daytot = DayInMonth(Mon, Yea);
  595.   x1 = (yea ? 30 : 24)*gi.nScaleT; y1 = unit*2;
  596.   x2 = gs.xWin - x1; y2 = gs.yWin - y1;
  597.   xs = x2 - x1; ys = y2 - y1;
  598.  
  599.   /* Display glyphs of the zodiac along the bottom axis. */
  600.  
  601.   for (i = 1; i <= cSign+1; i++) {
  602.     m = x1 + NMultDiv(xs, i-1, 12);
  603.     j = i > cSign ? 1 : i;
  604.     DrawColor(kSignB(j));
  605.     DrawSign(j, m, y2 + unit);
  606.     DrawColor(gi.kiGray);
  607.     DrawDash(m, y1, m, y2, 2);
  608.   }
  609.  
  610.   /* Loop and display planet movements for one day segment. */
  611.  
  612.   while (d <= daytot + 1) {
  613.     n = v;
  614.     v = y1 + NMultDiv(ys, d-1, daytot);
  615.     if (!yea || day == 1) {
  616.       DrawColor(gi.kiGray);
  617.       DrawDash(x1, v, x2, v, 1);    /* Marker line for day or month. */
  618.     }
  619.     if (d > 1)
  620.       for (i = 1; i <= cObj; i++)
  621.         objSav[i] = planet[i];
  622.     ciCore = ciMain;
  623.     if (yea) {
  624.       MM = mon; DD = day;
  625.     } else {
  626.       MM = Mon; DD = d;
  627.     }
  628.     CastChart(fTrue);
  629.  
  630.     /* Draw planet glyphs along top of chart. */
  631.  
  632.     if (d < 2) {
  633.       for (i = 1; i <= cObj; i++) {
  634.         j = !FProper(i) || (i == oMoo && gs.fAlt);
  635.         symbol[i*2-1] = (j || us.nRel > rcDual) ? -rLarge : cp2.obj[i];
  636.         symbol[i*2] = (j ? -rLarge : planet[i]);
  637.       }
  638.       FillSymbolLine(symbol);
  639.       for (i = cObj*2; i >= 1; i--) {
  640.         j = (i+1) >> 1;
  641.         if (symbol[i] >= 0.0)
  642.           DrawObject(j, x1 + (int)((real)xs * symbol[i] / rDegMax), unit);
  643.       }
  644.       if (us.nRel <= rcDual) {
  645.         for (i = cObj; i >= 1; i--) {
  646.           if (!FProper(i) || (i == oMoo && gs.fAlt))
  647.             continue;
  648.           j = x1 + (int)((real)xs * cp2.obj[i] / rDegMax);
  649.           DrawColor(kObjB[i]);
  650.           DrawDash(j, y1, j, y2, 1);
  651.         }
  652.       }
  653.  
  654.     /* Draw a line segment for each object during this time section. */
  655.  
  656.     } else
  657.       for (i = cObj; i >= 1; i--) {
  658.         if (!FProper(i) || (i == oMoo && gs.fAlt))
  659.           continue;
  660.         m = x1 + (int)((real)xs * objSav[i] / rDegMax);
  661.         u = x1 + (int)((real)xs * planet[i] / rDegMax);
  662.         DrawColor(kObjB[i]);
  663.         DrawWrap(m, n, u, v, ret[i] > 0.0 ? -x1 : x1, x2);
  664.       }
  665.  
  666.     /* Label months or days in the month along the left and right edges. */
  667.  
  668.     if (d <= daytot && (!yea || day == 1)) {
  669.       if (yea) {
  670.         sprintf(sz, "%c%c%c", chMon3(mon));
  671.         i = (mon == Mon);
  672.       } else {
  673.         sprintf(sz, "%2d", d);
  674.         i = (d == Day);
  675.       }
  676.       DrawColor(i ? gi.kiOn : gi.kiLite);
  677.       DrawSz(sz,     xFont   *gi.nScaleT, v + (yFont-2)*gi.nScaleT,
  678.         dtLeft | dtBottom);
  679.       DrawSz(sz, x2+(xFont-1)*gi.nScaleT, v + (yFont-2)*gi.nScaleT,
  680.         dtLeft | dtBottom);
  681.     }
  682.  
  683.     /* Now increment the day counter. For a month we always go up by one. */
  684.     /* For a year we go up by four or until the end of the month reached. */
  685.  
  686.     if (yea) {
  687.       i = us.fSeconds ? 2 : 4;
  688.       day += i;
  689.       if (day > monsiz) {
  690.         d += i-(day-monsiz-1);
  691.         if (d <= daytot + 1) {
  692.           mon++;
  693.           monsiz = DayInMonth(mon, Yea);
  694.           day = 1;
  695.         }
  696.       } else
  697.         d += i;
  698.     } else
  699.       d++;
  700.   }
  701.   DrawColor(gi.kiLite);
  702.   DrawEdge(x1, y1, x2, y2);
  703.  
  704.   ciCore = ciMain;    /* Recast original chart. */
  705.   CastChart(fTrue);
  706. }
  707.  
  708.  
  709. #ifdef BIORHYTHM
  710. /* Draw a graphic biorhythm chart on the screen, as is done when the -rb    */
  711. /* switch is combined with -X. This is technically a relationship chart in  */
  712. /* that biorhythm status is determined by a natal chart time at another     */
  713. /* later time. For the day in question, and for two weeks before and after, */
  714. /* the Physical, Emotional, and Mental percentages are plotted.             */
  715.  
  716. void XChartBiorhythm()
  717. {
  718.   char sz[6], *c;
  719.   real jd, r, a;
  720.   int x1, x2, xs, cx, y1, y2, ys, cy, i, j, k, x, y, x0, y0;
  721.  
  722.   k = xFont*6*gi.nScaleT;
  723.   x1 = k; x2 = gs.xWin-k; xs = x2-x1; cx = (x1+x2)/2;
  724.   k = CELLSIZE;
  725.   y1 = k; y2 = gs.yWin-k; ys = y2-y1; cy = (y1+y2)/2;
  726.  
  727.   /* Create a dotted day/percentage grid to graph on. */
  728.   DrawColor(gi.kiGray);
  729.   DrawDash(x1, cy, x2, cy, 1);
  730.   DrawDash(cx, y1, cx, y2, 1);
  731.   for (j = -us.nBioday+1; j <= us.nBioday-1; j++) {
  732.     x = x1 + NMultDiv(xs, j+us.nBioday, us.nBioday*2);
  733.     for (k = -90; k <= 90; k += 10) {
  734.       y = y1 + NMultDiv(ys, 100+k, 200);
  735.       DrawPoint(x, y);
  736.     }
  737.   }
  738.  
  739.   /* Now actually draw the three biorhythm curves. */
  740.   for (i = 1; i <= 3; i++) {
  741.     jd = RFloor(is.JD + rRound);
  742.     switch (i) {
  743.     case 1: r = brPhy; c = "PHYS"; j = eFir; break;
  744.     case 2: r = brEmo; c = "EMOT"; j = eWat; break;
  745.     case 3: r = brInt; c = "INTE"; j = eEar; break;
  746.     }
  747.     DrawColor(kElemB[j]);
  748.     for (jd -= (real)us.nBioday, j = -us.nBioday; j <= us.nBioday;
  749.       j++, jd += 1.0) {
  750.       a = RBiorhythm(jd, r);
  751.       x = x1 + NMultDiv(xs, j+us.nBioday, us.nBioday*2);
  752.       y = y1 + (int)((real)ys * (100.0-a) / 200.0);
  753.       if (j > -us.nBioday)
  754.         DrawLine(x0, y0, x, y);
  755.       else
  756.         DrawSz(c, x1/2, y+2*gi.nScaleT, dtCent);
  757.       x0 = x; y0 = y;
  758.     }
  759.   }
  760.  
  761.   DrawColor(gi.kiLite);
  762.   /* Label biorhythm percentages along right vertical axis. */
  763.   for (k = -100; k <= 100; k += 10) {
  764.     sprintf(sz, "%c%3d%%", k < 0 ? '-' : '+', abs(k));
  765.     y = y1 + NMultDiv(ys, 100-k, 200);
  766.     DrawSz(sz, (x2+gs.xWin)/2, y+2*gi.nScaleT, dtCent);
  767.   }
  768.   /* Label days on top horizontal axis. */
  769.   k = Max(us.nBioday/7, 1);
  770.   for (j = -us.nBioday+k; j < us.nBioday; j += k) {
  771.     x = x1 + NMultDiv(xs, j+us.nBioday, us.nBioday*2);
  772.     sprintf(sz, "%c%d", j < 0 ? '-' : '+', abs(j));
  773.     DrawSz(sz, x, y1-2*gi.nScaleT, dtBottom);
  774.   }
  775.   DrawEdge(x1, y1, x2, y2);
  776. }
  777. #endif /* BIORHYTHM */
  778. #endif /* GRAPH */
  779.  
  780. /* xcharts2.c */
  781.